package cn.bone.ou.vote.service.impl;

import cn.bone.base.annotation.MyLogger;
import cn.bone.base.auth.JWTInfo;
import cn.bone.base.bean.CommonResult;
import cn.bone.base.bean.DataGrid;
import cn.bone.base.bean.Ref;
import cn.bone.base.utils.TimeUtil;
import cn.bone.base.utils.ValidUtil;
import cn.bone.ou.community.bean.Community;
import cn.bone.ou.community.mapper.CommunityMapper;
import cn.bone.ou.data.bean.CommunityArticle;
import cn.bone.ou.data.bean.CommunityFile;
import cn.bone.ou.data.mapper.CommunityArticleMapper;
import cn.bone.ou.data.mapper.CommunityFileMapper;
import cn.bone.ou.user.mapper.UserMapper;
import cn.bone.ou.vote.bean.*;
import cn.bone.ou.vote.dto.VoteDto;
import cn.bone.ou.vote.mapper.*;
import cn.bone.ou.vote.param.VoteParam;
import cn.bone.ou.vote.service.IVoteService;
import cn.bone.ou.vote.vo.VoteVo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Transactional
@Slf4j
public class VoteServiceImpl implements IVoteService {

    @Resource
    private CommunityMapper communityMapper;
    @Resource
    private VoteInfoMapper infoMapper;
    @Resource
    private VoteDetailMapper detailMapper;
    @Resource
    private VoteExtraMapper extraMapper;
    @Resource
    private VoteItemMapper itemMapper;
    @Resource
    private VoteOptionMapper optionMapper;
    @Resource
    private VoteResultMapper resultMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private CommunityFileMapper fileMapper;
    @Resource
    private CommunityArticleMapper articleMapper;


    /**新增投票*/
    @MyLogger(msg = "新增投票")
    public CommonResult add(VoteParam.AddParam param){

        VoteParam.VoteJson json = null;
        try {
            json = JSON.parseObject(param.getVoteJson(), VoteParam.VoteJson.class);
        }catch (Exception e){
            log.error("投票json数据解析失败");
        }
        if(json==null){
            return Ref.error("json数据不正确");
        }
        String msg = ValidUtil.validate(json);
        if(msg!=null){
            return Ref.error(msg);
        }
        Date startTime = TimeUtil.parseYYYYMMddHHmm(json.getStartTime());
        if(startTime==null){
            return Ref.error("开始时间格式错误");
        }
        Date endTime = TimeUtil.parseYYYYMMddHHmm(json.getEndTime());
        if(endTime==null){
            return Ref.error("结束时间格式错误");
        }
        Community community = communityMapper.selectById(param.getCommunityId());
        if(community==null){
            return Ref.error("错误的小区编号");
        }
        /** 校验结束 **/

        Date now = new Date();
        Integer userId = JWTInfo.get().getUserId();

        //添加基本信息
        VoteInfo info = new VoteInfo();
        info.setCommunityId(param.getCommunityId());
        info.setVoteRange(json.getRange());
        info.setTitle(json.getTitle());
        info.setStartTime(startTime);
        info.setEndTime(endTime);
//        info.setContent(json.getContent());
        info.setCreateTime(now);
        info.setCreateUserId(userId);
        info.setState(0);
        infoMapper.insert(info);

        VoteDetail detail = new VoteDetail();
        detail.setVoteId(info.getId());
        detail.setContent(json.getContent());
        detailMapper.insert(detail);

        //添加附件
        if(json.getExtras()!=null && json.getExtras().size()>0){
            for(int i=0;i<json.getExtras().size();i++){
                VoteParam.VoteExtraJson extraJson = json.getExtras().get(i);
                VoteExtra extra = new VoteExtra();
                extra.setCommunityId(info.getCommunityId());
                extra.setVoteId(info.getId());
                extra.setExtraType(extraJson.getExtraType());
                extra.setDetailId(extraJson.getDetailId());
                extra.setOrderNum(i+1);
                extra.setCreateTime(now);
                extra.setCreateUserId(userId);
                extraMapper.insert(extra);
            }
        }

        //添加事项
        if(json.getItems()!=null && json.getItems().size()>0){
            for(int i=0;i<json.getItems().size();i++){
                VoteParam.VoteItemJson itemJson = json.getItems().get(i);
                VoteItem item = new VoteItem();
                item.setCommunityId(info.getCommunityId());
                item.setVoteId(info.getId());
                item.setTitle(itemJson.getTitle());
                item.setItemType(itemJson.getItemType());
                item.setChooseNum(itemJson.getChooseNum());
                item.setOrderNum(i+1);
                item.setCreateTime(now);
                item.setCreateUserId(userId);
                itemMapper.insert(item);

                //添加选项
                if(itemJson.getOptions()!=null && itemJson.getOptions().size()>0){
                    for(int j=0;j<itemJson.getOptions().size();j++){
                        VoteParam.optionJson optionJson = itemJson.getOptions().get(j);
                        VoteOption option = new VoteOption();
                        option.setCommunityId(info.getCommunityId());
                        option.setVoteId(info.getId());
                        option.setItemId(item.getId());
                        option.setAnswerOption(optionJson.getAnswerOption());
                        option.setAnswerContent(optionJson.getAnswerContent());
                        option.setOrderNum(j+1);
                        option.setCreateTime(now);
                        option.setCreateUserId(userId);
                        optionMapper.insert(option);
                    }
                }
            }
        }
        return Ref.ok();
    }

    /**修改投票*/
    @MyLogger(msg = "修改投票")
    public CommonResult modify(VoteParam.ModifyParam param){
        VoteParam.VoteJson json = null;
        try {
            json = JSON.parseObject(param.getVoteJson(), VoteParam.VoteJson.class);
        }catch (Exception e){
            log.error("投票json数据解析失败");
        }
        if(json==null){
            return Ref.error("json数据不正确");
        }
        String msg = ValidUtil.validate(json);
        if(msg!=null){
            return Ref.error(msg);
        }
        Date startTime = TimeUtil.parseYYYYMMddHHmm(json.getStartTime());
        if(startTime==null){
            return Ref.error("开始时间格式错误");
        }
        Date endTime = TimeUtil.parseYYYYMMddHHmm(json.getEndTime());
        if(endTime==null){
            return Ref.error("结束时间格式错误");
        }
        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        VoteDetail detail = detailMapper.getByVoteId(info.getId());
        if(detail==null){
            return Ref.error("投票数据错误");
        }
        Integer state = info.getState();
        if(state==2){
            return Ref.error("投票已经终止,不能修改");
        }
        if(state==3||state==4||state==5){
            return Ref.error("投票已发布,不能修改");
        }
        /** 校验结束 **/

        //先删除
        extraMapper.delteByVoteId(param.getVoteId());
        itemMapper.delteByVoteId(param.getVoteId());
        optionMapper.delteByVoteId(param.getVoteId());

        info.setVoteRange(json.getRange());
        info.setTitle(json.getTitle());
        info.setStartTime(startTime);
        info.setEndTime(endTime);
//        info.setContent(json.getContent());
        infoMapper.updateById(info);

        detail.setContent(json.getContent());
        detailMapper.updateById(detail);

        Date now = new Date();
        Integer userId = JWTInfo.get().getUserId();
        //添加附件
        if(json.getExtras()!=null && json.getExtras().size()>0){
            for(int i=0;i<json.getExtras().size();i++){
                VoteParam.VoteExtraJson extraJson = json.getExtras().get(i);
                VoteExtra extra = new VoteExtra();
                extra.setCommunityId(info.getCommunityId());
                extra.setVoteId(info.getId());
                extra.setExtraType(extraJson.getExtraType());
                extra.setDetailId(extraJson.getDetailId());
                extra.setOrderNum(i+1);
                extra.setCreateTime(now);
                extra.setCreateUserId(userId);
                extraMapper.insert(extra);
            }
        }

        //添加事项
        if(json.getItems()!=null && json.getItems().size()>0){
            for(int i=0;i<json.getItems().size();i++){
                VoteParam.VoteItemJson itemJson = json.getItems().get(i);
                VoteItem item = new VoteItem();
                item.setCommunityId(info.getCommunityId());
                item.setVoteId(info.getId());
                item.setTitle(itemJson.getTitle());
                item.setItemType(itemJson.getItemType());
                item.setChooseNum(itemJson.getChooseNum());
                item.setOrderNum(i+1);
                item.setCreateTime(now);
                item.setCreateUserId(userId);
                itemMapper.insert(item);

                //添加选项
                if(itemJson.getOptions()!=null && itemJson.getOptions().size()>0){
                    for(int j=0;j<itemJson.getOptions().size();j++){
                        VoteParam.optionJson optionJson = itemJson.getOptions().get(j);
                        VoteOption option = new VoteOption();
                        option.setCommunityId(info.getCommunityId());
                        option.setVoteId(info.getId());
                        option.setItemId(item.getId());
                        option.setAnswerOption(optionJson.getAnswerOption());
                        option.setAnswerContent(optionJson.getAnswerContent());
                        option.setOrderNum(j+1);
                        option.setCreateTime(now);
                        option.setCreateUserId(userId);
                        optionMapper.insert(option);
                    }
                }
            }
        }
        return Ref.ok();
    }

    /**列表*/
    public CommonResult<DataGrid<VoteVo.ListVo>> list(VoteParam.ListParam param){

        //先获取小区业主总数
        int countYz = userMapper.countYz(param.getCommunityId());
        //再获取列表
        List<VoteDto.ListDto> dtos = infoMapper.list(param.getCommunityId(),
                param.getStart(), param.getNum(),
                param.getTitle(), param.getState());
        int count = infoMapper.countList(param.getCommunityId(),
                param.getTitle(),param.getState());

        List<VoteVo.ListVo> vos = dtos.stream().map(dto->{
            VoteVo.ListVo vo = new VoteVo.ListVo();
            vo.setVoteId(dto.getId());
            vo.setTitle(dto.getTitle());
            vo.setStartTime(TimeUtil.formaterYYYYMMddHHmm(dto.getStartTime()));
            vo.setEndTime(TimeUtil.formaterYYYYMMddHHmm(dto.getEndTime()));
            vo.setState(dto.getState());
            String handCount = dto.getVoteCount() + "/" + countYz;
            vo.setHandCount(handCount);
            return vo;
        }).collect(Collectors.toList());

        DataGrid<VoteVo.ListVo> dataGrid = new DataGrid<>();
        dataGrid.setRows(vos);
        dataGrid.setTotal(count);
        return Ref.ok(dataGrid);
    }

    /**发布*/
    @MyLogger(msg = "发布投票")
    public CommonResult publish(VoteParam.PublishParam param){
        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        Integer state = info.getState();
        if(state==3||state==4||state==5){
            return Ref.error("投票已发布");
        }
        if(state==2){
            return Ref.error("投票已终止,不能发布");
        }

        long now = new Date().getTime();
        long start = info.getStartTime().getTime();
        long end = info.getEndTime().getTime();
        if(now<start){
            info.setState(3);
        }else if(now<end){
            info.setState(4);
        }else{
            info.setState(5);
        }
        infoMapper.updateById(info);
        return Ref.ok();
    }

    /**取消发布*/
    @MyLogger(msg = "取消发布投票")
    public CommonResult unpublish(VoteParam.UnpublishParam param){
        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        Integer state = info.getState();
        if(state==0||state==1||state==2){
            return Ref.error("投票还未发布");
        }
        if(state==5){
            return Ref.error("投票已结束,不能取消");
        }
        info.setState(1);
        infoMapper.updateById(info);
        return Ref.ok();
    }

    /**终止投票*/
    @MyLogger(msg = "终止投票")
    public CommonResult stop(VoteParam.StopParam param){
        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        Integer state = info.getState();
        if(state==3||state==4||state==5){
            return Ref.error("投票已发布,不能终止");
        }
        if(state==2){
            return Ref.error("投票已终止");
        }
        info.setState(2);
        infoMapper.updateById(info);
        return Ref.ok();
    }

    /**获取详情*/
    public CommonResult<VoteVo.DetailVo> detail(VoteParam.DetailParam param){
        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        VoteDetail detail = detailMapper.getByVoteId(param.getVoteId());
        if(detail==null){
            return Ref.error("投票数据错误");
        }

        VoteVo.DetailVo vo = new VoteVo.DetailVo();
        vo.setVoteId(info.getId());
        vo.setVoteRange(info.getVoteRange());
        vo.setTitle(info.getTitle());
        vo.setStartTime(TimeUtil.formaterYYYYMMddHHmm(info.getStartTime()));
        vo.setEndTime(TimeUtil.formaterYYYYMMddHHmm(info.getEndTime()));
        vo.setContent(detail.getContent());
        vo.setState(info.getState());

        //添加附件
        List<VoteExtra> extras = extraMapper.listByVoteId(param.getVoteId());
        for(VoteExtra extra : extras){
            VoteVo.ExtraVo evo = new VoteVo.ExtraVo();
            evo.setExtraType(extra.getExtraType());
            evo.setOrderNum(extra.getOrderNum());
            evo.setDetailId(extra.getDetailId());

            //文件
            if(extra.getExtraType()==1){
                CommunityFile file = fileMapper.selectById(extra.getDetailId());
                if(file!=null){
                    evo.setName(file.getName());
                    evo.setUrl(file.getUrl());
                    vo.getExtras().add(evo);
                }
            }
            //文章
            else if(extra.getExtraType()==2){
                CommunityArticle article = articleMapper.selectById(extra.getDetailId());
                if(article!=null){
                    evo.setName(article.getTitle());
                    vo.getExtras().add(evo);
                }
            }
        }

        //添加事项
        List<VoteItem> items = itemMapper.list(param.getVoteId());
        for(VoteItem item : items){
            VoteVo.ItemVo itemVo = new VoteVo.ItemVo();
            itemVo.setTitle(item.getTitle());
            itemVo.setItemType(item.getItemType());
            itemVo.setChooseNum(item.getChooseNum());
            itemVo.setOrderNum(item.getOrderNum());

            List<VoteOption> options = optionMapper.list(item.getId());
            for(VoteOption option : options){
                VoteVo.OptionVo optionVo = new VoteVo.OptionVo();
                optionVo.setAnswerOption(option.getAnswerOption());
                optionVo.setAnswerContent(option.getAnswerContent());
                itemVo.getOptions().add(optionVo);
            }
            vo.getItems().add(itemVo);
        }
        return Ref.ok(vo);
    }

    /**删除投票*/
    @MyLogger(msg = "删除投票")
    public CommonResult delete(VoteParam.DeleteParam param){

        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        VoteDetail detail = detailMapper.getByVoteId(param.getVoteId());
        if(detail==null){
            return Ref.error("投票数据错误");
        }
        if(info.getState()!=2){
            return Ref.error("只有状态为已终止的投票才能删除");
        }

        infoMapper.deleteById(param.getVoteId());
        detailMapper.deleteById(detail.getId());
        extraMapper.delteByVoteId(param.getVoteId());
        itemMapper.delteByVoteId(param.getVoteId());
        optionMapper.delteByVoteId(param.getVoteId());
        resultMapper.delteByVoteId(param.getVoteId());
        return Ref.ok();
    }

    /**结果统计*/
    public CommonResult<List<VoteVo.ResultDetailVo>> resultDetail(VoteParam.ResultDetailParam param){
        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        Integer state = info.getState();
        if(state!=4 && state!=5){
            return Ref.error("只有进行中和已完成的投票才能查看结果");
        }

        List<VoteDto.ResultDetailDto> dtos = resultMapper.listResultDetail(param.getVoteId());
        Map<Integer, List<VoteDto.ResultDetailDto>> dataMap = new LinkedHashMap<>();
        for(VoteDto.ResultDetailDto dto : dtos){
            List<VoteDto.ResultDetailDto> dtoList = dataMap.get(dto.getItemId());
            if(dtoList==null){
                dtoList = new ArrayList<>();
                dataMap.put(dto.getItemId(),dtoList);
            }
            dtoList.add(dto);
        }

        List<VoteVo.ResultDetailVo> vos = new ArrayList<>();
        Iterator<Map.Entry<Integer, List<VoteDto.ResultDetailDto>>> iterator = dataMap.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<Integer, List<VoteDto.ResultDetailDto>> next = iterator.next();
            Integer key = next.getKey();
            List<VoteDto.ResultDetailDto> value = next.getValue();
            VoteVo.ResultDetailVo vo = new VoteVo.ResultDetailVo();
            vo.setTitle(value.get(0).getTitle());
            for(VoteDto.ResultDetailDto dto : value){
                VoteVo.ResultOptionVo ovo = new VoteVo.ResultOptionVo();
                ovo.setAnswerOption(dto.getAnswerOption());
                ovo.setAnswerContent(dto.getAnswerContent());
                ovo.setCount(dto.getOptionCount());
                ovo.setPercentage("0");
                vo.getOptions().add(ovo);
            }
            vos.add(vo);
        }

        //计算百分比
        DecimalFormat df = new DecimalFormat("#.00");
        for(VoteVo.ResultDetailVo vo : vos){
            List<VoteVo.ResultOptionVo> options = vo.getOptions();
            Integer sum = 0;
            for(VoteVo.ResultOptionVo option : options){
                sum = sum + option.getCount();
            }
            for(VoteVo.ResultOptionVo option : options){
                if(sum==0){
                    option.setPercentage("0");
                }else{

                    double percentage = option.getCount().doubleValue() / sum.doubleValue() * 100;
                    BigDecimal b = new BigDecimal(percentage);
                    String s = b.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
                    option.setPercentage(s);
                }
            }
        }
        return Ref.ok(vos);
    }

    /**全部投票*/
    public CommonResult<DataGrid<VoteVo.MemberDetailVo>> memberDetail(VoteParam.MemberDetailParam param){

        VoteInfo info = infoMapper.selectById(param.getVoteId());
        if(info==null){
            return Ref.error("错误的投票编号");
        }
        Integer state = info.getState();
        if(state!=4 && state!=5){
            return Ref.error("只有进行中和已完成的投票才能查看结果");
        }

        List<VoteDto.MemberDetailDto> dtos = resultMapper.listMemberDetail(param.getVoteId(),
                param.getStart(), param.getNum());
        int count = resultMapper.countListMemberDetail(param.getVoteId());
        List<VoteVo.MemberDetailVo> vos = dtos.stream().map(dto->{
            VoteVo.MemberDetailVo vo = new VoteVo.MemberDetailVo();
            vo.setUserId(dto.getUserId());
            vo.setRealName(dto.getRealName());
            vo.setPhoneNum(dto.getPhoneNum());
            vo.setGender(dto.getGender());
            vo.setIdCard(dto.getIdCard());
            vo.setBuildNum(dto.getBuildNum());
            vo.setUnitNum(dto.getUnitNum());
            vo.setHouseNum(dto.getHouseNum());
            vo.setCreateTime(TimeUtil.formaterYYYYMMddHHmm(dto.getCreateTime()));
            return vo;
        }).collect(Collectors.toList());
        DataGrid<VoteVo.MemberDetailVo> dataGrid = new DataGrid<>();
        dataGrid.setTotal(count);
        dataGrid.setRows(vos);
        return Ref.ok(dataGrid);
    }

    /**用户投票详情*/
    public CommonResult<List<VoteVo.MemberVoteDetailVo>> memberVoteDetail(VoteParam.MemberVoteDetailParam param){
        List<VoteDto.MemberVoteDetailDto> dtos = resultMapper.listMemberVoteDetail(
                param.getVoteId(), param.getUserId());

        Map<Integer,List<VoteDto.MemberVoteDetailDto>> map = new LinkedHashMap<>();
        for(VoteDto.MemberVoteDetailDto dto : dtos){
            List<VoteDto.MemberVoteDetailDto> dtoList = map.get(dto.getItemId());
            if(dtoList==null){
                dtoList = new ArrayList<>();
                map.put(dto.getItemId(),dtoList);
            }
            dtoList.add(dto);
        }
        List<VoteVo.MemberVoteDetailVo> vos = new ArrayList<>();
        Iterator<Map.Entry<Integer, List<VoteDto.MemberVoteDetailDto>>> iterator = map.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<Integer, List<VoteDto.MemberVoteDetailDto>> next = iterator.next();
            List<VoteDto.MemberVoteDetailDto> value = next.getValue();
            VoteVo.MemberVoteDetailVo vo = new VoteVo.MemberVoteDetailVo();
            vo.setTitle(value.get(0).getTitle());
            for(VoteDto.MemberVoteDetailDto dto : value){
                VoteVo.MemberVoteDetailOptionVo ovo = new VoteVo.MemberVoteDetailOptionVo();
                ovo.setAnswerOption(dto.getAnswerOption());
                ovo.setAnswerContent(dto.getAnswerContent());
                ovo.setHasChoose(dto.getHasChoose());
                vo.getOptions().add(ovo);
            }
            vos.add(vo);
        }
        return Ref.ok(vos);
    }
}
